package flextestng.testing.utils
{
	import flash.display.Loader;
	import flash.display.LoaderInfo;
	import flash.events.Event;
	import flash.events.IOErrorEvent;
	import flash.filesystem.File;
	import flash.filesystem.FileMode;
	import flash.filesystem.FileStream;
	import flash.system.ApplicationDomain;
	import flash.system.LoaderContext;
	import flash.utils.ByteArray;
	
	import mx.events.ModuleEvent;
	
	public class TestModuleLoader
	{
		private var _listeners:Array = [];
		private var _loader:Loader = new Loader();
		private var _module:File;
		
		public function TestModuleLoader(module:File)
		{
			_module = module;
		}
		
		public function addModuleListener(listener:IModuleLoaderListener):void
		{
			var i:int = _listeners.indexOf(listener);
			
			if (i == -1) {
				_listeners.push(listener);
			}
		}
		
		public function dispose():void
		{
			unload();
			
			_listeners.splice(0, _listeners.length);
		}
		
		private function fireError(error:String):void
		{
			for each (var l:IModuleLoaderListener in _listeners) {
				l.error(error);
			}
		}
		
		private function fireReady():void
		{
			for each (var l:IModuleLoaderListener in _listeners) {
				l.ready();
			}
		}
		
		private function handleComplete(event:Event):void
		{
			var moduleLoader:LoaderInfo = LoaderInfo( event.target );
			
			// is this even possible?
			moduleLoader.content.addEventListener(ModuleEvent.ERROR, handleModuleError);
			
			// lets know when this is ready.
			moduleLoader.content.addEventListener(ModuleEvent.READY, handleModuleReady);
		}
		
		private function handleIOError(event:IOErrorEvent):void
		{
			fireError("Module load error: " + event.text);
		}
		
		private function handleModuleError(event:Event):void
		{
			fireError("Module load error: unknown");
		}
		
		private function handleModuleReady(event:Event):void
		{
			fireReady();
		}
		
		public function load():void
		{
			var stream:FileStream = new FileStream();
			stream.open(_module, FileMode.READ);
			
			var bytes:ByteArray = new ByteArray();
			stream.readBytes(bytes, 0, stream.bytesAvailable);
			stream.close();
			
			var context:LoaderContext = new LoaderContext();
			context.allowLoadBytesCodeExecution = true;
			context.applicationDomain = ApplicationDomain.currentDomain;
			
			_loader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, handleIOError);
			_loader.contentLoaderInfo.addEventListener(Event.COMPLETE, handleComplete);
			_loader.loadBytes(bytes, context);
		}
		
		public function removeModuleListener(listener:IModuleLoaderListener):void
		{
			var i:int = _listeners.indexOf(listener);
			
			if (i != -1) {
				_listeners.splice(i, 1);
			}
		}
		
		public function unload():void
		{
			_loader.unload();
		}
	}
}